// @import
import MsgSchema from "./MsgSchema";
import OutParam from "../util/OutParam";

/**
 * 内置字典, 
 * key = strMsgID | nMsgCode
 */
const g_oInnerMap: Map<string | number, MsgSchema> = new Map();

/**
 * 消息识别器
 */
export default class MsgRecognizer {
    /**
     * 私有化类默认构造器
     */
    private constructor() {
    }

    /**
     * 添加协议
     * 
     * @param strProtocolName 协议名称
     * @param oUsingProtocol 使用协议
     */
    static addProtocol(strProtocolName: string, oUsingProtocol: any): void {
        if (null == strProtocolName ||
            null == oUsingProtocol) {
            return;
        }

        __addProtocol(strProtocolName, oUsingProtocol);
    }

    /**
     * 根据名称移除协议
     * 
     * @param strProtocolName 协议名称
     */
    static removeProtocol(strProtocolName: string): void {
        if (null == strProtocolName) {
            return;
        }

        let oDeletingKeyArray: Array<number | string> = [];

        g_oInnerMap.forEach((oVal, oKey) => {
            if (null == oVal ||
                oVal._strProtocolName == strProtocolName) {
                oDeletingKeyArray.push(oKey);
            }
        });

        oDeletingKeyArray.forEach((oVal) => {
            g_oInnerMap.delete(oVal);
        });
    }

    /**
     * 根据消息编码获取消息类
     * 
     * @param nMsgCode 消息编码
     * @param out_oMsgName ( 输出参数 ) 消息名称
     * @return 消息类
     */
    static getMsgClazzByMsgCode(nMsgCode: number, out_oMsgName: OutParam<string> = null): any {
        if (nMsgCode < 0) {
            return null;
        }

        let oMsgSchema: MsgSchema = g_oInnerMap.get(nMsgCode);

        if (null == oMsgSchema) {
            return null;
        }

        if (null != out_oMsgName) {
            out_oMsgName.put(oMsgSchema._strMsgName);
        }

        return oMsgSchema._oMsgClazz;
    }
}

///////////////////////////////////////////////////////////////////////

/**
 * 完成内部映射
 * 
 * @param strProtocolName 协议名称
 * @param oUsingProtocol 使用协议
 * @returns
 */
function __addProtocol(strProtocolName: string, oUsingProtocol: any): void {
    if (null == oUsingProtocol ||
        null == oUsingProtocol["msg"] ||
        null == oUsingProtocol["msg"]["MsgCode"]) {
        return;
    }

    let oMsgPackageX: any = oUsingProtocol["msg"];
    let oMsgCodeEnum: any = oUsingProtocol["msg"]["MsgCode"];

    // 先遍历所有的消息代号, 将数字塞到字典 0 里
    for (let oKey in oMsgCodeEnum) {
        if ("string" != typeof oKey ||
            "number" != typeof oMsgCodeEnum[oKey]) {
            continue;
        }

        let strMsgID: string = oKey.split("_").join("").toLocaleLowerCase();
        let nMsgCode: number = oMsgCodeEnum[oKey];

        let oMsgSchema: MsgSchema = {
            _strMsgID: strMsgID,
            _nMsgCode: nMsgCode,
            _strMsgName: "",
            _oMsgClazz: null,
            _strProtocolName: strProtocolName,
            _oUsingProtocol: oUsingProtocol,
        };

        g_oInnerMap.set(nMsgCode, oMsgSchema);
        g_oInnerMap.set(strMsgID, oMsgSchema);
    }

    // 再遍历所有的消息类, 将类定义塞到字典 1 里
    for (let strMsgClazzName in oMsgPackageX) {
        if (!strMsgClazzName.endsWith("Broadcast") &&
            !strMsgClazzName.endsWith("Cmd") &&
            !strMsgClazzName.endsWith("Result")) {
            continue;
        }

        let strMsgID: string = strMsgClazzName.split("_").join("").toLocaleLowerCase();
        let oMsgSchema: MsgSchema = g_oInnerMap.get(strMsgID);

        if (null == oMsgSchema) {
            continue;
        }

        console.log(`消息映射 :: ${oMsgSchema._nMsgCode} <==> ${strMsgClazzName}`);

        // 填补消息名称和消息类
        oMsgSchema._strMsgName = strMsgClazzName;
        oMsgSchema._oMsgClazz = oMsgPackageX[strMsgClazzName];
    }
}
